home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-10 | 15.2 KB | 746 lines | [TEXT/KAHL] |
- /*
- ** CTelnetTerminal.cp
- **
- ** MiniTelnet application
- ** Telnet terminal session document
- **
- ** Copyright © 1993, FrostByte Design / Eric Scouten
- **
- */
-
-
- #include "CTelnetTerminal.h"
-
- #ifndef TurboTCPHeaders
- #include <Packages.h>
- #include <Global.h>
- #include <Commands.h>
- #include <TCLUtilities.h>
- #include <TBUtilities.h>
- #include <CApplication.h>
- #include <CDesktop.h>
- #include <CBartender.h>
- #include <CClipboard.h>
- #include <CDecorator.h>
- #include <CScrollPane.h>
- #include <CWindow.h>
- #endif
-
- #include <CFile.h>
- #include "CTCPDriver.h"
- #include "CTCPStream.h"
- #include "CTCPResolverCall.h"
- #include "CTerminalPane.h"
-
-
- // global TCL objects
-
- extern CApplication *gApplication;
- extern CBartender *gBartender;
- extern CClipboard *gClipboard;
- extern CDecorator *gDecorator;
- extern CDesktop *gDesktop;
-
-
- // global TurboTCP objects
-
- extern CTCPDriver *gTCPDriver;
-
-
- // —— initialization ——
-
- /*______________________________________________________________________
- **
- ** ITelnetTerminal
- **
- ** Initialize the Telnet terminal session document.
- **
- ** aSupervisor (CApplication *): the document’s supervisor
- ** printable (Boolean): TRUE if document is printable
- ** recBufferSize (long): size of the receive buffer we need
- ** theDefaultPort (b_16): default IP port number
- ** autoReceiveSize (long): number of entries in RDS for auto-receive,
- ** 0 to disable autoreceiving
- ** autoReceiveNum (short): number of auto-receive calls to issue at once
- ** must be at least 1
- **
- */
-
- void CTelnetTerminal::ITelnetTerminal (CApplication *aSupervisor, Boolean printable,
- long recBufferSize, b_16 theDefaultPort,
- short autoReceiveSize, short autoReceiveNum)
-
- {
- itsTerminal = NULL;
- itsTermMode = 0;
- CTelnetInterpreter::ITelnetInterpreter(aSupervisor, printable, recBufferSize,
- theDefaultPort, autoReceiveSize, autoReceiveNum);
- showFileName = FALSE;
- }
-
-
- // —— creating new sessions ——
-
- /*______________________________________________________________________
- **
- ** NewSession
- **
- ** Create a new window for document. Pulls information from the settings record which
- ** it receives and opens a session accordingly.
- **
- ** theSettings (TelnetSettingsRec *): the settings record to use
- **
- */
-
- void CTelnetTerminal::NewSession (TelnetSettingsRec *theSettings)
-
- {
- // copy the settings record
-
- BlockMove(theSettings, &r, sizeof (TelnetSettingsRec));
- BlockMove(&r.hostName, &hostCName, 256);
- goAwayOnClose = r.closeOnSessionEnd;
- showDebug = r.showDebug;
-
- // build a window immediately
-
- BuildWindow();
-
- // open host by name
-
- #if _TestTerminal
- itsTerminal->DoWriteStr("No TCP session. Just type onto terminal.\r\n");
- #else
- itsStream->SetULPTimeoutValue(20);
- OpenUserHost((char *) &r.hostName, defaultPort, TRUE);
- #endif
-
- }
-
-
- /*______________________________________________________________________
- **
- ** BuildWindow
- **
- ** Build a window for a terminal connection.
- **
- */
-
- void CTelnetTerminal::BuildWindow (void)
-
- {
- CScrollPane *theScrollPane;
- CTerminalPane *theMainPane;
- Rect sizeRect;
-
- // create a window
-
- itsWindow = new(CWindow);
- itsWindow->IWindow(WINDTelnet, FALSE, gDesktop, this);
-
- // set maximum size of window
-
- SetRect(&sizeRect, 100, 100, sizeX+16, sizeY+16);
- itsWindow->SetSizeRect(&sizeRect);
-
- // create the scrolling pane
-
- theScrollPane = new(CScrollPane);
- theScrollPane->IScrollPane(itsWindow, this, 10, 10, 0, 0,
- sizELASTIC, sizELASTIC,
- TRUE, TRUE, TRUE);
- theScrollPane->FitToEnclFrame(TRUE, TRUE);
-
- // create the main view pane
-
- theMainPane = new(CTerminalPane);
- theMainPane->ITerminalPane(theScrollPane, this, 0, 0, 0, 0,
- sizELASTIC, sizELASTIC);
- itsMainPane = theMainPane;
- itsTerminal = theMainPane;
- itsGopher = theMainPane;
- theMainPane->FitToEnclosure(TRUE, TRUE);
-
- // make sure the scroll pane knows about the panorama
-
- theScrollPane->InstallPanorama(theMainPane);
-
- // place, size, and title the window
-
- gDecorator->PlaceNewWindow(itsWindow);
- AutoTitle();
- itsWindow->Select();
-
- }
-
-
- /*______________________________________________________________________
- **
- ** AutoTitle
- **
- ** Sets title for window. Turns on or off cursor blinking depending on whether session
- ** is established.
- **
- */
-
- void CTelnetTerminal::AutoTitle (void)
-
- {
- CTCPSessionDoc::AutoTitle();
- itsTerminal->SetBlinking(sessionReady);
- }
-
-
- // —— command/event handling ——
-
- /*______________________________________________________________________
- **
- ** DoCommand
- **
- ** Handle all commands document can understand.
- **
- ** theCommand (long): command number that was issued
- **
- */
-
- void CTelnetTerminal::DoCommand (long theCommand)
-
- {
- char addrStr [18]; // used for send IP addr command
-
- switch (theCommand) {
-
- // Edit menu: support pasting TEXT
-
- case cmdPaste:
- DoPaste();
- break;
-
- // Telnet menu: send various strings to server
-
- case cmdSendSynch:
- if (showDebug)
- PrintDebugStr("{Urgent IAC DM}");
- itsStream->SetNextUrgent(FALSE);
- itsStream->SendCString("\377\362");
- break;
-
- case cmdSendBreak:
- if (showDebug)
- PrintDebugStr("{Urgent IAC BRK IAC DM}");
- itsStream->SetNextUrgent(FALSE);
- itsStream->SendCString("\377\363\377\362");
- break;
-
- case cmdSendAO:
- if (showDebug)
- PrintDebugStr("{Urgent IAC AO IAC DM}");
- itsStream->SetNextUrgent(FALSE);
- itsStream->SendCString("\377\365\377\362");
- break;
-
- case cmdSendIP:
- if (showDebug)
- PrintDebugStr("{Urgent IAC IP IAC DM}");
- itsStream->SetNextUrgent(FALSE);
- itsStream->SendCString("\377\364\377\362");
- break;
-
- case cmdSendAYT:
- if (showDebug)
- PrintDebugStr("{Urgent IAC AYT IAC DM}");
- itsStream->SetNextUrgent(FALSE);
- itsStream->SendCString("\377\366\377\362");
- break;
-
- case cmdSendGA:
- if (showDebug)
- PrintDebugStr("{IAC GA}");
- itsStream->SendCString("\377\371");
- break;
-
- case cmdSendEC:
- if (showDebug)
- PrintDebugStr("{IAC EC}");
- itsStream->SendCString("\377\367");
- break;
-
- case cmdSendEL:
- if (showDebug)
- PrintDebugStr("{IAC EL}");
- itsStream->SendCString("\377\370");
- break;
-
- case cmdSendIPAddr:
- itsResolver->DoAddrToStr(gTCPDriver->GetIPAddr(),
- (char *) &addrStr);
- itsStream->SendCString((char *) &addrStr);
- break;
-
- case cmdShowDebug:
- showDebug = !showDebug;
- r.showDebug = showDebug;
- break;
-
- // not ours, send along the chain
-
- default:
- inherited::DoCommand(theCommand);
- }
- }
-
-
- /*______________________________________________________________________
- **
- ** DoKeyDown
- **
- ** Process key-down events. Parses CR, LF codes and generates the
- ** standard CR/LF sequence when CR is passed and ignores LF.
- **
- ** theChar (char): the character that was entered
- ** keyCode (byte): the Mac ADB key number for the key that was pressed
- ** macEvent (EventRecord *): the entire event record
- **
- */
-
- void CTelnetTerminal::DoKeyDown (char theChar, Byte keyCode, EventRecord *macEvent)
-
- {
-
- // make sure this isn’t an errant command key
-
- if (!((*macEvent).modifiers & cmdKey)) {
- if (theChar != charLF) {
- #if _TestTerminal
- HandleNVTChar(theChar);
- if (theChar == charCR)
- HandleNVTChar(charLF);
- #else
- if (!sessionReady) {
- SysBeep(0);
- return;
- }
-
- if (theChar == charBS)
- itsStream->SendChar(r.backspaceChar);
- else
- itsStream->SendChar(theChar);
-
- if (theChar == charCR)
- itsStream->SendChar(charLF);
- #endif
- itsTerminal->ScrollToSelection();
- }
- }
-
- }
-
-
- /*______________________________________________________________________
- **
- ** DoAutoKey
- **
- ** Process automatic (repeated) key-down events.
- **
- ** theChar (char): the character that was entered
- ** keyCode (byte): the Mac ADB key number for the key that was pressed
- ** macEvent (EventRecord *): the entire event record
- **
- */
-
- void CTelnetTerminal::DoAutoKey (char theChar, Byte keyCode, EventRecord *macEvent)
-
- {
- DoKeyDown(theChar, keyCode, macEvent); // boy, wasn’t that simple!
- }
-
-
- /*______________________________________________________________________
- **
- ** DoPaste
- **
- ** Respond to Paste command by sending all characters from the
- ** clipboard to the remote host.
- **
- */
-
- void CTelnetTerminal::DoPaste (void)
-
- {
- Handle theData;
- char lineBfr[83];
- char *p, *pl, *lb;
- long rem;
- short i;
-
- // get the clipboard contents
-
- if (!(gClipboard->GetData('TEXT', &theData)))
- return;
- HLock(theData);
-
- // send it in line or 80-char chunks
-
- p = *theData;
- rem = GetHandleSize(theData);
-
- while (rem > 0) {
-
- // fetch a line (or 81 chars)
-
- i = 0;
- pl = p;
- lb = &lineBfr[0];
- while ((rem-(i) > 0) && (*pl != charCR) && (i < 80))
- i++, *lb++ = *pl++;
- if (*pl == charCR) {
- i++, *pl++;
- *lb++ = charCR;
- *lb++ = charLF;
- }
- *lb = '\0';
-
- // send the line
-
- #if _TestTerminal
- HandleNVTLine((char *) &lineBfr);
- #else
- itsStream->SendBfrCpy((char *) &lineBfr, cstrlen(lineBfr));
- #endif
-
- rem -= i;
- p += i;
-
- }
-
- HUnlock(theData);
- DisposHandle(theData);
- }
-
-
- /*______________________________________________________________________
- **
- ** UpdateMenus
- **
- ** Enable Telnet-specific commands.
- **
- */
-
- void CTelnetTerminal::UpdateMenus (void)
-
- {
- CDocument::UpdateMenus();
-
- // enable “Paste” command only if valid Clipboard
-
- #if _TestTerminal
- if (gClipboard->DataSize('TEXT'))
- gBartender->EnableCmd(cmdPaste);
- #else
- if (sessionReady && (gClipboard->DataSize('TEXT')))
- gBartender->EnableCmd(cmdPaste);
- #endif
-
-
- // enable “Send…” commands only if session is active
-
- if (sessionReady) {
- gBartender->EnableCmd(cmdSendSynch);
- gBartender->EnableCmd(cmdSendBreak);
- gBartender->EnableCmd(cmdSendAO);
- gBartender->EnableCmd(cmdSendIP);
- gBartender->EnableCmd(cmdSendAYT);
- gBartender->EnableCmd(cmdSendGA);
- gBartender->EnableCmd(cmdSendEC);
- gBartender->EnableCmd(cmdSendEL);
- gBartender->EnableCmd(cmdSendIPAddr);
- gBartender->EnableCmd(cmdShowDebug);
- gBartender->CheckMarkCmd(cmdShowDebug, showDebug);
- }
-
- }
-
-
- // —— data handling methods ——
-
- /*______________________________________________________________________
- **
- ** HandleNVTChar
- **
- ** Process a character which was recieved over Telnet for the network virtual terminal.
- **
- ** theChar (char): the character which was received
- **
- */
-
- void CTelnetTerminal::HandleNVTChar (char theChar)
-
- {
- itsTerminal->DoWriteChar(theChar);
- }
-
-
- /*______________________________________________________________________
- **
- ** HandleNVTLine
- **
- ** Process a line (or <81 chars) which was recieved over Telnet for the network virtual
- ** terminal.
- **
- ** theLine (char *): the line which was received (C string)
- **
- */
-
- void CTelnetTerminal::HandleNVTLine (char *theLine)
-
- {
- itsTerminal->DoWriteStr(theLine);
- }
-
-
- // —— Telnet command handling ——
-
-
- /*______________________________________________________________________
- **
- ** ReceivedDo
- **
- ** Respond to a Telnet [IAC DO option] sequence.
- **
- ** theOption (uChar): the option code
- **
- */
-
- void CTelnetTerminal::ReceivedDo (uchar theOption)
-
- {
- uchar respondStr[4];
-
- // parse the option and respond to it
-
- switch (theOption) {
-
- // accept terminal type option only
-
- case optTERMINAL_TYPE:
- respondStr[0] = charIAC;
- respondStr[1] = escWILL;
- respondStr[2] = theOption;
- respondStr[3] = '\0';
- if (showDebug) {
- PrintDebugStr("{IAC WILL");
- PrintDebugCharNum(theOption, ' ', '}');
- }
- itsStream->SendCString((char *) &respondStr);
- break;
-
- // reject the remaining options
-
- default:
- CTelnetInterpreter::ReceivedDo(theOption);
- }
-
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedAYT
- **
- ** Respond to a Telnet [IAC AYT] sequence.
- **
- */
-
- void CTelnetTerminal::ReceivedAYT (void)
-
- {
- if (showDebug)
- PrintDebugStr("{Yes}");
- itsStream->SendCString("[Yes]");
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedEC
- **
- ** Respond to a Telnet [IAC EC] sequence.
- **
- */
-
- void CTelnetTerminal::ReceivedEC (void)
-
- {
- itsTerminal->DoEraseChar();
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedEL
- **
- ** Respond to a Telnet [IAC EL] sequence.
- **
- */
-
- void CTelnetTerminal::ReceivedEL (void)
-
- {
- itsTerminal->DoEraseLine();
- }
-
-
- /*______________________________________________________________________
- **
- ** ReceivedSE
- **
- ** Parse subnegotiation parameters. Called when [IAC SE] is received.
- **
- */
-
- void CTelnetTerminal::ReceivedSE (void)
-
- {
- // dispatch to an option-parsing routine
-
- if (sbBfrIndex < 1)
- return;
- switch (sbBfr[0]) {
-
- case optTERMINAL_TYPE:
- OptionTerminalType();
- break;
-
- default:
- CTelnetInterpreter::ReceivedSE();
- }
-
- }
-
-
- // —— Telnet option handling ——
-
- /*______________________________________________________________________
- **
- ** OptionTerminalType
- **
- ** Interpret an [IAC SB TERMINAL-TYPE ... IAC SE] sequence. Default method always says
- ** this is an unknown terminal.
- **
- */
-
- void CTelnetTerminal::OptionTerminalType (void)
-
- {
- uchar respondStr [47];
- short i = 2;
-
- // respond only to TERMINAL-TYPE SEND queries; ignore others
-
- if (sbBfr[1] == 1) {
-
- // build a response string
-
- respondStr[0] = charIAC;
- respondStr[1] = escSB;
- respondStr[2] = optTERMINAL_TYPE;
-
- // switch to next terminal emulation
-
- itsTermMode++;
- if (itsTermMode > termMax)
- itsTermMode = 0;
- // SetTerminalMode(itsTermMode);
-
- // get name of terminal emulation
-
- GetTerminalName(itsTermMode, &respondStr[3]);
-
- // display response if debugging mode enabled
-
- if (showDebug) {
- PrintDebugStr("{IAC SB TERM-TYPE IS ");
- PrintDebugStr((char *) &respondStr[3]);
- PrintDebugStr(" IAC SE}");
- }
-
- // add end of SB string & send it
-
- while (respondStr[++i])
- ;
- respondStr[i] = charIAC;
- respondStr[i+1] = escSE;
- respondStr[i+2] = '\0';
- itsStream->SendCString((char *) &respondStr);
- }
-
- }
-
-
- // —— terminal emulation handling ——
-
- /*______________________________________________________________________
- **
- ** GetTerminalName
- **
- ** Return the Internet assigned name for the terminal being used.
- **
- ** termIndex (short): the terminal emulation number
- ** termStr (uchar *): buffer to receive the terminal name (max 40 chars)
- **
- */
-
- void CTelnetTerminal::GetTerminalName (short termIndex, uchar *termStr)
-
- {
- uchar theTerm[41] = "UNKNOWN"; // for now, all we have is “UNKNOWN”
- BlockMove(&theTerm, termStr, 41);
- }
-
-
- /*______________________________________________________________________
- **
- ** —— debugging methods ——
- **
- ** These methods were useful to me in debugging the implementation of various Telnet
- ** options. They are enabled by the “Show debugging codes” option of the settings dialog.
- **
- */
-
- /*______________________________________________________________________
- **
- ** PrintDebugStr
- **
- ** Write a string to the terminal for debugging purposes.
- **
- ** theDebugStr (char *): the string to write
- **
- */
-
- void CTelnetTerminal::PrintDebugStr (char *theDebugStr)
-
- {
- itsTerminal->DoWriteStr(theDebugStr);
- }
-
-
- /*______________________________________________________________________
- **
- ** PrintDebugCharNum
- **
- ** Print a character number for debugging. Provided as a debugging routine. The number
- ** is bracketed by the two characters indicated, i.e. if you call PrintDebugCharNum('!', '[', ']'),
- ** you get [33] written to the terminal.
- **
- ** theChar (char): the character number to write
- ** leftBracket (char): prefix to character number
- ** rightBracket (char): suffix to character number
- **
- */
-
- void CTelnetTerminal::PrintDebugCharNum (char theChar, char leftBracket, char rightBracket)
-
- {
- itsTerminal->DoWriteCharNum(theChar, leftBracket, rightBracket);
- }
-